import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectClassDemo {

    //创建对象（创建类的实例）
    public static void reflectNewInstance() {
        Class<?> c1 = null;
        try {
            c1 = Class.forName("Student");
            Student student = (Student) c1.newInstance();

            System.out.println(student);
        }catch (ClassNotFoundException
                | InstantiationException
                | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    // 反射私有的构造方法 屏蔽内容为获得公有的 "构造方法"
    //获得类中构造器相关的方法
    //
    //getConstructor(Class...<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
    //getConstructors() 获得该类的所有公有构造方法
    //getDeclaredConstructor(Class...<?> parameterTypes) 获得该类中与参数类型匹配的构造方法
    //getDeclaredConstructors() 获得该类所有构造方法
    //
    public static void reflectPrivateConstructor() {
        Class<Student> c1 = null;
        try {
            c1 = (Class<Student>)Class.forName("Student");
            //注意传入对应的参数
            //getDeclaredConstructor(Class...<?> parameterTypes) 获得该类中与参数类型匹配的构造方法
            Constructor<Student> constructor = c1.getDeclaredConstructor(String.class,int.class);

            //设置为true后可修改访问权限
            constructor.setAccessible(true);//改为可以访问并修改，不然会报错不给你改

            Student student = constructor.newInstance("遂",151);

            System.out.println(student);
        }catch (ClassNotFoundException |
                InstantiationException |
                IllegalAccessException |
                NoSuchMethodException |
                InvocationTargetException e){

            e.printStackTrace();
        }
    }


    // 反射私有属性

    //getField(String name) 获得某个公有的属性对象
    //getFields() 获得所有公有的属性对象
    //getDeclaredField(String name) 获得某个属性对象
    //getDeclaredFields() 获得所有属性对象


    public static void reflectPrivateField() {
        Class<?> c1 = null;
        try {

            c1 = Class.forName("Student");
            Field field = c1.getDeclaredField("name");//获得某个属性对象
            field.setAccessible(true);//因为name是私有的要改的话必须变成ture

            Student student = (Student)c1.newInstance();

            field.set(student,"沸羊羊");

            System.out.println(student);

        }catch (ClassNotFoundException
                | NoSuchFieldException
                | InstantiationException
                | IllegalAccessException
                e) {
            e.printStackTrace();
        }
    }

    //反射私有方法
    //getMethod(String name, Class...<?> parameterTypes) 获得该类某个公有的方法
    //getMethods() 获得该类所有公有的方法
    //getDeclaredMethod(String name, Class...<?> parameterTypes) 获得该类某个方法
    //getDeclaredMethods() 获得该类所有方法
    public static void reflectPrivateMethod() {
        Class<?> c1 = null;
        try {

            c1 = (Class<Student>) Class.forName("Student");
            Method method = c1.getDeclaredMethod("function",String.class);//获得该类某个方法

            method.setAccessible(true);//因为name是私有的要改的话必须变成ture

            Student student = (Student)c1.newInstance();

            method.invoke(student,"hello everyone");


        }catch (ClassNotFoundException
                | InstantiationException
                | IllegalAccessException
                | NoSuchMethodException
                |InvocationTargetException
                e) {
            e.printStackTrace();
        }
    }

    //优点：
    //1. 对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意一个方法
    //2. 增加程序的灵活性和扩展性，降低耦合性，提高自适应能力
    //3. 反射已经运用在了很多流行框架如：Struts、Hibernate、Spring 等等。
    //缺点：
    //1. 使用反射会有效率问题。会导致程序效率降低。具体参考这里：http://www.imooc.com/article/293679
    //2. 反射技术绕过了源代码的技术，因而会带来维护问题。反射代码比相应的直接代码更复杂 。


    public static void main(String[] args) {
        //reflectNewInstance();

        //reflectPrivateConstructor();

        //reflectPrivateField();

        reflectPrivateMethod();
    }
}
